package com.xc.stock.aop.distributedlock;

import java.util.concurrent.TimeUnit;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;

import com.ag.exception.SysTipsException;
import com.ag.utils.CollectionUtils;
import com.xc.stock.aop.annotation.DistributedLock;
import com.xc.stock.aop.annotation.DistributedLocks;

import lombok.Builder;
import lombok.Data;

@Builder
@Data
public class DistributedLockInfo {
	String lockName;
	String message;
	Long leaseTime; 
	TimeUnit timeUnit; 
	Boolean fairLock;
	
	public static DistributedLockInfo[] build(DistributedLocks annotations, Object[] args) {
		if(CollectionUtils.isEmpty(annotations.value())) {
			throw new SysTipsException("DistributedLocks.values() 不能为空");
		}
		
		DistributedLockInfo[] array = new DistributedLockInfo[annotations.value().length];
		for (int i = 0; i < annotations.value().length; i++) {
			array[i] = build(annotations.value()[i], args);
		}
		return array;
	}
	
	public static DistributedLockInfo build(String lockName, String message) {
		return DistributedLockInfo.builder()
			.lockName(lockName)
			.message(message)
			.leaseTime(5L)
			.timeUnit(TimeUnit.SECONDS)
			.fairLock(false)
			.build();
	}
	
	public static DistributedLockInfo build(DistributedLock annotation, Object[] args) {
		return DistributedLockInfo.builder()
			.lockName(getLockName(annotation, args))
			.message(annotation.desc())
			.leaseTime(annotation.leaseTime())
			.timeUnit(annotation.timeUnit())
			.fairLock(annotation.fairLock())
			.build();
	}
	
	public static String getLockName(DistributedLock annotation, Object[] args) {
		String lockName = annotation.lockName(), param = annotation.param();

		if (StringUtils.isEmpty(lockName)) {
			if (args.length > 0) {
				if (StringUtils.isNotEmpty(param)) {
					Object arg;
					if (annotation.argNum() > 0) {
						arg = args[annotation.argNum() - 1];
					} else {
						arg = args[0];
					}
					lockName = String.valueOf(getParam(arg, param));
				} else if (annotation.argNum() > 0) {
					lockName = args[annotation.argNum() - 1].toString();
				}
			}
		}

		if (StringUtils.isNotEmpty(lockName)) {
			String preLockName = annotation.lockNamePre(), 
					postLockName = annotation.lockNamePost(),
					separator = annotation.separator();

			StringBuilder lName = new StringBuilder();
			if (StringUtils.isNotEmpty(preLockName)) {
				lName.append(preLockName).append(separator);
			}
			
			lName.append(lockName);
			if (StringUtils.isNotEmpty(postLockName)) {
				lName.append(separator).append(postLockName);
			}

			lockName = lName.toString();
			return lockName;
		}

		throw new IllegalArgumentException("Can't get or generate lockName accurately!");
	}
	
	
	/**
	 * 从方法参数获取数据
	 *
	 * @param param
	 * @param arg
	 *            方法的参数数组
	 * @return
	 */
	public static Object getParam(Object arg, String param) {
		if (StringUtils.isNotEmpty(param) && arg != null) {
			try {
				Object result = PropertyUtils.getProperty(arg, param);
				return result;
			} catch (NoSuchMethodException e) {
				throw new IllegalArgumentException(arg + "没有属性" + param + "或未实现get方法。", e);
			} catch (Exception e) {
				throw new RuntimeException("", e);
			}
		}
		return null;
	}
}
